1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package javax.swing.text;
26
27 import java.lang.reflect.Method;
28
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31
32 import java.beans.Transient;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.Hashtable;
36 import java.util.Enumeration;
37 import java.util.Vector;
38 import java.util.Map;
39
40 import java.util.concurrent.*;
41
42 import java.io.*;
43
44 import java.awt.*;
45 import java.awt.event.*;
46 import java.awt.print.*;
47 import java.awt.datatransfer.*;
48 import java.awt.im.InputContext;
49 import java.awt.im.InputMethodRequests;
50 import java.awt.font.TextHitInfo;
51 import java.awt.font.TextAttribute;
52
53 import java.awt.print.Printable;
54 import java.awt.print.PrinterException;
55
56 import javax.print.PrintService;
57 import javax.print.attribute.PrintRequestAttributeSet;
58
59 import java.text.*;
60 import java.text.AttributedCharacterIterator.Attribute;
61
62 import javax.swing.*;
63 import javax.swing.event.*;
64 import javax.swing.plaf.*;
65
66 import javax.accessibility.*;
67
68 import javax.print.attribute.*;
69
70 import sun.awt.AppContext;
71
72
73 import sun.swing.PrintingStatus;
74 import sun.swing.SwingUtilities2;
75 import sun.swing.text.TextComponentPrintable;
76 import sun.swing.SwingAccessor;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 public abstract class JTextComponent extends JComponent implements Scrollable, Accessible
304 {
305
306
307
308
309
310
311
312 public JTextComponent() {
313 super();
314
315 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK);
316 caretEvent = new MutableCaretEvent(this);
317 addMouseListener(caretEvent);
318 addFocusListener(caretEvent);
319 setEditable(true);
320 setDragEnabled(false);
321 setLayout(null);
322 updateUI();
323 }
324
325
326
327
328
329
330 public TextUI getUI() { return (TextUI)ui; }
331
332
333
334
335
336
337 public void setUI(TextUI ui) {
338 super.setUI(ui);
339 }
340
341
342
343
344
345
346
347 public void updateUI() {
348 setUI((TextUI)UIManager.getUI(this));
349 invalidate();
350 }
351
352
353
354
355
356
357
358
359 public void addCaretListener(CaretListener listener) {
360 listenerList.add(CaretListener.class, listener);
361 }
362
363
364
365
366
367
368
369 public void removeCaretListener(CaretListener listener) {
370 listenerList.remove(CaretListener.class, listener);
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 public CaretListener[] getCaretListeners() {
387 return listenerList.getListeners(CaretListener.class);
388 }
389
390
391
392
393
394
395
396
397
398
399
400 protected void fireCaretUpdate(CaretEvent e) {
401
402 Object[] listeners = listenerList.getListenerList();
403
404
405 for (int i = listeners.length-2; i>=0; i-=2) {
406 if (listeners[i]==CaretListener.class) {
407 ((CaretListener)listeners[i+1]).caretUpdate(e);
408 }
409 }
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425 public void setDocument(Document doc) {
426 Document old = model;
427
428
429
430
431
432 try {
433 if (old instanceof AbstractDocument) {
434 ((AbstractDocument)old).readLock();
435 }
436 if (accessibleContext != null) {
437 model.removeDocumentListener(
438 ((AccessibleJTextComponent)accessibleContext));
439 }
440 if (inputMethodRequestsHandler != null) {
441 model.removeDocumentListener((DocumentListener)inputMethodRequestsHandler);
442 }
443 model = doc;
444
445
446
447 Boolean runDir = getComponentOrientation().isLeftToRight()
448 ? TextAttribute.RUN_DIRECTION_LTR
449 : TextAttribute.RUN_DIRECTION_RTL;
450 if (runDir != doc.getProperty(TextAttribute.RUN_DIRECTION)) {
451 doc.putProperty(TextAttribute.RUN_DIRECTION, runDir );
452 }
453 firePropertyChange("document", old, doc);
454 } finally {
455 if (old instanceof AbstractDocument) {
456 ((AbstractDocument)old).readUnlock();
457 }
458 }
459
460 revalidate();
461 repaint();
462 if (accessibleContext != null) {
463 model.addDocumentListener(
464 ((AccessibleJTextComponent)accessibleContext));
465 }
466 if (inputMethodRequestsHandler != null) {
467 model.addDocumentListener((DocumentListener)inputMethodRequestsHandler);
468 }
469 }
470
471
472
473
474
475
476
477
478
479
480 public Document getDocument() {
481 return model;
482 }
483
484
485 public void setComponentOrientation( ComponentOrientation o ) {
486
487
488 Document doc = getDocument();
489 if( doc != null ) {
490 Boolean runDir = o.isLeftToRight()
491 ? TextAttribute.RUN_DIRECTION_LTR
492 : TextAttribute.RUN_DIRECTION_RTL;
493 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir );
494 }
495 super.setComponentOrientation( o );
496 }
497
498
499
500
501
502
503
504
505
506
507 public Action[] getActions() {
508 return getUI().getEditorKit(this).getActions();
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526 public void setMargin(Insets m) {
527 Insets old = margin;
528 margin = m;
529 firePropertyChange("margin", old, m);
530 invalidate();
531 }
532
533
534
535
536
537
538
539 public Insets getMargin() {
540 return margin;
541 }
542
543
544
545
546
547
548
549
550 public void setNavigationFilter(NavigationFilter filter) {
551 navigationFilter = filter;
552 }
553
554
555
556
557
558
559
560
561
562
563 public NavigationFilter getNavigationFilter() {
564 return navigationFilter;
565 }
566
567
568
569
570
571
572
573 @Transient
574 public Caret getCaret() {
575 return caret;
576 }
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591 public void setCaret(Caret c) {
592 if (caret != null) {
593 caret.removeChangeListener(caretEvent);
594 caret.deinstall(this);
595 }
596 Caret old = caret;
597 caret = c;
598 if (caret != null) {
599 caret.install(this);
600 caret.addChangeListener(caretEvent);
601 }
602 firePropertyChange("caret", old, caret);
603 }
604
605
606
607
608
609
610 public Highlighter getHighlighter() {
611 return highlighter;
612 }
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629 public void setHighlighter(Highlighter h) {
630 if (highlighter != null) {
631 highlighter.deinstall(this);
632 }
633 Highlighter old = highlighter;
634 highlighter = h;
635 if (highlighter != null) {
636 highlighter.install(this);
637 }
638 firePropertyChange("highlighter", old, h);
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654 public void setKeymap(Keymap map) {
655 Keymap old = keymap;
656 keymap = map;
657 firePropertyChange("keymap", old, keymap);
658 updateInputMap(old, map);
659 }
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694 public void setDragEnabled(boolean b) {
695 if (b && GraphicsEnvironment.isHeadless()) {
696 throw new HeadlessException();
697 }
698 dragEnabled = b;
699 }
700
701
702
703
704
705
706
707
708 public boolean getDragEnabled() {
709 return dragEnabled;
710 }
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 public final void setDropMode(DropMode dropMode) {
739 if (dropMode != null) {
740 switch (dropMode) {
741 case USE_SELECTION:
742 case INSERT:
743 this.dropMode = dropMode;
744 return;
745 }
746 }
747
748 throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for text");
749 }
750
751
752
753
754
755
756
757
758 public final DropMode getDropMode() {
759 return dropMode;
760 }
761
762 static {
763 SwingAccessor.setJTextComponentAccessor(
764 new SwingAccessor.JTextComponentAccessor() {
765 public TransferHandler.DropLocation dropLocationForPoint(JTextComponent textComp,
766 Point p)
767 {
768 return textComp.dropLocationForPoint(p);
769 }
770 public Object setDropLocation(JTextComponent textComp,
771 TransferHandler.DropLocation location,
772 Object state, boolean forDrop)
773 {
774 return textComp.setDropLocation(location, state, forDrop);
775 }
776 });
777 }
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793 DropLocation dropLocationForPoint(Point p) {
794 Position.Bias[] bias = new Position.Bias[1];
795 int index = getUI().viewToModel(this, p, bias);
796
797
798
799 if (bias[0] == null) {
800 bias[0] = Position.Bias.Forward;
801 }
802
803 return new DropLocation(p, index, bias[0]);
804 }
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845 Object setDropLocation(TransferHandler.DropLocation location,
846 Object state,
847 boolean forDrop) {
848
849 Object retVal = null;
850 DropLocation textLocation = (DropLocation)location;
851
852 if (dropMode == DropMode.USE_SELECTION) {
853 if (textLocation == null) {
854 if (state != null) {
855
856
857
858
859
860
861
862
863
864
865
866
867
868 Object[] vals = (Object[])state;
869
870 if (!forDrop) {
871 if (caret instanceof DefaultCaret) {
872 ((DefaultCaret)caret).setDot(((Integer)vals[0]).intValue(),
873 (Position.Bias)vals[3]);
874 ((DefaultCaret)caret).moveDot(((Integer)vals[1]).intValue(),
875 (Position.Bias)vals[4]);
876 } else {
877 caret.setDot(((Integer)vals[0]).intValue());
878 caret.moveDot(((Integer)vals[1]).intValue());
879 }
880 }
881
882 caret.setVisible(((Boolean)vals[2]).booleanValue());
883 }
884 } else {
885 if (dropLocation == null) {
886 boolean visible;
887
888 if (caret instanceof DefaultCaret) {
889 DefaultCaret dc = (DefaultCaret)caret;
890 visible = dc.isActive();
891 retVal = new Object[] {Integer.valueOf(dc.getMark()),
892 Integer.valueOf(dc.getDot()),
893 Boolean.valueOf(visible),
894 dc.getMarkBias(),
895 dc.getDotBias()};
896 } else {
897 visible = caret.isVisible();
898 retVal = new Object[] {Integer.valueOf(caret.getMark()),
899 Integer.valueOf(caret.getDot()),
900 Boolean.valueOf(visible)};
901 }
902
903 caret.setVisible(true);
904 } else {
905 retVal = state;
906 }
907
908 if (caret instanceof DefaultCaret) {
909 ((DefaultCaret)caret).setDot(textLocation.getIndex(), textLocation.getBias());
910 } else {
911 caret.setDot(textLocation.getIndex());
912 }
913 }
914 } else {
915 if (textLocation == null) {
916 if (state != null) {
917 caret.setVisible(((Boolean)state).booleanValue());
918 }
919 } else {
920 if (dropLocation == null) {
921 boolean visible = caret instanceof DefaultCaret
922 ? ((DefaultCaret)caret).isActive()
923 : caret.isVisible();
924 retVal = Boolean.valueOf(visible);
925 caret.setVisible(false);
926 } else {
927 retVal = state;
928 }
929 }
930 }
931
932 DropLocation old = dropLocation;
933 dropLocation = textLocation;
934 firePropertyChange("dropLocation", old, dropLocation);
935
936 return retVal;
937 }
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957 public final DropLocation getDropLocation() {
958 return dropLocation;
959 }
960
961
962
963
964
965
966
967
968 void updateInputMap(Keymap oldKm, Keymap newKm) {
969
970 InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
971 InputMap last = km;
972 while (km != null && !(km instanceof KeymapWrapper)) {
973 last = km;
974 km = km.getParent();
975 }
976 if (km != null) {
977
978
979 if (newKm == null) {
980 if (last != km) {
981 last.setParent(km.getParent());
982 }
983 else {
984 last.setParent(null);
985 }
986 }
987 else {
988 InputMap newKM = new KeymapWrapper(newKm);
989 last.setParent(newKM);
990 if (last != km) {
991 newKM.setParent(km.getParent());
992 }
993 }
994 }
995 else if (newKm != null) {
996 km = getInputMap(JComponent.WHEN_FOCUSED);
997 if (km != null) {
998
999
1000 InputMap newKM = new KeymapWrapper(newKm);
1001 newKM.setParent(km.getParent());
1002 km.setParent(newKM);
1003 }
1004 }
1005
1006
1007 ActionMap am = getActionMap();
1008 ActionMap lastAM = am;
1009 while (am != null && !(am instanceof KeymapActionMap)) {
1010 lastAM = am;
1011 am = am.getParent();
1012 }
1013 if (am != null) {
1014
1015
1016 if (newKm == null) {
1017 if (lastAM != am) {
1018 lastAM.setParent(am.getParent());
1019 }
1020 else {
1021 lastAM.setParent(null);
1022 }
1023 }
1024 else {
1025 ActionMap newAM = new KeymapActionMap(newKm);
1026 lastAM.setParent(newAM);
1027 if (lastAM != am) {
1028 newAM.setParent(am.getParent());
1029 }
1030 }
1031 }
1032 else if (newKm != null) {
1033 am = getActionMap();
1034 if (am != null) {
1035
1036
1037 ActionMap newAM = new KeymapActionMap(newKm);
1038 newAM.setParent(am.getParent());
1039 am.setParent(newAM);
1040 }
1041 }
1042 }
1043
1044
1045
1046
1047
1048
1049
1050 public Keymap getKeymap() {
1051 return keymap;
1052 }
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 public static Keymap addKeymap(String nm, Keymap parent) {
1070 Keymap map = new DefaultKeymap(nm, parent);
1071 if (nm != null) {
1072
1073 getKeymapTable().put(nm, map);
1074 }
1075 return map;
1076 }
1077
1078
1079
1080
1081
1082
1083
1084
1085 public static Keymap removeKeymap(String nm) {
1086 return getKeymapTable().remove(nm);
1087 }
1088
1089
1090
1091
1092
1093
1094
1095
1096 public static Keymap getKeymap(String nm) {
1097 return getKeymapTable().get(nm);
1098 }
1099
1100 private static HashMap<String,Keymap> getKeymapTable() {
1101 synchronized (KEYMAP_TABLE) {
1102 AppContext appContext = AppContext.getAppContext();
1103 HashMap<String,Keymap> keymapTable =
1104 (HashMap<String,Keymap>)appContext.get(KEYMAP_TABLE);
1105 if (keymapTable == null) {
1106 keymapTable = new HashMap<String,Keymap>(17);
1107 appContext.put(KEYMAP_TABLE, keymapTable);
1108
1109 Keymap binding = addKeymap(DEFAULT_KEYMAP, null);
1110 binding.setDefaultAction(new
1111 DefaultEditorKit.DefaultKeyTypedAction());
1112 }
1113 return keymapTable;
1114 }
1115 }
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129 public static class KeyBinding {
1130
1131
1132
1133
1134 public KeyStroke key;
1135
1136
1137
1138
1139 public String actionName;
1140
1141
1142
1143
1144
1145
1146
1147 public KeyBinding(KeyStroke key, String actionName) {
1148 this.key = key;
1149 this.actionName = actionName;
1150 }
1151 }
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188 public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) {
1189 Hashtable<String, Action> h = new Hashtable<String, Action>();
1190 for (Action a : actions) {
1191 String value = (String)a.getValue(Action.NAME);
1192 h.put((value!=null ? value:""), a);
1193 }
1194 for (KeyBinding binding : bindings) {
1195 Action a = h.get(binding.actionName);
1196 if (a != null) {
1197 map.addActionForKeyStroke(binding.key, a);
1198 }
1199 }
1200 }
1201
1202
1203
1204
1205
1206
1207
1208
1209 private static Boolean isProcessInputMethodEventOverridden(Class<?> klass) {
1210 if (klass == JTextComponent.class) {
1211 return Boolean.FALSE;
1212 }
1213 Boolean retValue = overrideMap.get(klass.getName());
1214
1215 if (retValue != null) {
1216 return retValue;
1217 }
1218 Boolean sOverriden = isProcessInputMethodEventOverridden(
1219 klass.getSuperclass());
1220
1221 if (sOverriden.booleanValue()) {
1222
1223
1224 overrideMap.put(klass.getName(), sOverriden);
1225 return sOverriden;
1226 }
1227
1228
1229 try {
1230 Class[] classes = new Class[1];
1231 classes[0] = InputMethodEvent.class;
1232
1233 Method m = klass.getDeclaredMethod("processInputMethodEvent",
1234 classes);
1235 retValue = Boolean.TRUE;
1236 } catch (NoSuchMethodException nsme) {
1237 retValue = Boolean.FALSE;
1238 }
1239 overrideMap.put(klass.getName(), retValue);
1240 return retValue;
1241 }
1242
1243
1244
1245
1246
1247
1248
1249 public Color getCaretColor() {
1250 return caretColor;
1251 }
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266 public void setCaretColor(Color c) {
1267 Color old = caretColor;
1268 caretColor = c;
1269 firePropertyChange("caretColor", old, caretColor);
1270 }
1271
1272
1273
1274
1275
1276
1277
1278 public Color getSelectionColor() {
1279 return selectionColor;
1280 }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295 public void setSelectionColor(Color c) {
1296 Color old = selectionColor;
1297 selectionColor = c;
1298 firePropertyChange("selectionColor", old, selectionColor);
1299 }
1300
1301
1302
1303
1304
1305
1306
1307 public Color getSelectedTextColor() {
1308 return selectedTextColor;
1309 }
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324 public void setSelectedTextColor(Color c) {
1325 Color old = selectedTextColor;
1326 selectedTextColor = c;
1327 firePropertyChange("selectedTextColor", old, selectedTextColor);
1328 }
1329
1330
1331
1332
1333
1334
1335
1336 public Color getDisabledTextColor() {
1337 return disabledTextColor;
1338 }
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352 public void setDisabledTextColor(Color c) {
1353 Color old = disabledTextColor;
1354 disabledTextColor = c;
1355 firePropertyChange("disabledTextColor", old, disabledTextColor);
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371 public void replaceSelection(String content) {
1372 Document doc = getDocument();
1373 if (doc != null) {
1374 try {
1375 boolean composedTextSaved = saveComposedText(caret.getDot());
1376 int p0 = Math.min(caret.getDot(), caret.getMark());
1377 int p1 = Math.max(caret.getDot(), caret.getMark());
1378 if (doc instanceof AbstractDocument) {
1379 ((AbstractDocument)doc).replace(p0, p1 - p0, content,null);
1380 }
1381 else {
1382 if (p0 != p1) {
1383 doc.remove(p0, p1 - p0);
1384 }
1385 if (content != null && content.length() > 0) {
1386 doc.insertString(p0, content, null);
1387 }
1388 }
1389 if (composedTextSaved) {
1390 restoreComposedText();
1391 }
1392 } catch (BadLocationException e) {
1393 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
1394 }
1395 }
1396 }
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407 public String getText(int offs, int len) throws BadLocationException {
1408 return getDocument().getText(offs, len);
1409 }
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427 public Rectangle modelToView(int pos) throws BadLocationException {
1428 return getUI().modelToView(this, pos);
1429 }
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445 public int viewToModel(Point pt) {
1446 return getUI().viewToModel(this, pt);
1447 }
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458 public void cut() {
1459 if (isEditable() && isEnabled()) {
1460 invokeAction("cut", TransferHandler.getCutAction());
1461 }
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473 public void copy() {
1474 invokeAction("copy", TransferHandler.getCopyAction());
1475 }
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489 public void paste() {
1490 if (isEditable() && isEnabled()) {
1491 invokeAction("paste", TransferHandler.getPasteAction());
1492 }
1493 }
1494
1495
1496
1497
1498
1499
1500
1501
1502 private void invokeAction(String name, Action altAction) {
1503 ActionMap map = getActionMap();
1504 Action action = null;
1505
1506 if (map != null) {
1507 action = map.get(name);
1508 }
1509 if (action == null) {
1510 installDefaultTransferHandlerIfNecessary();
1511 action = altAction;
1512 }
1513 action.actionPerformed(new ActionEvent(this,
1514 ActionEvent.ACTION_PERFORMED, (String)action.
1515 getValue(Action.NAME),
1516 EventQueue.getMostRecentEventTime(),
1517 getCurrentEventModifiers()));
1518 }
1519
1520
1521
1522
1523
1524 private void installDefaultTransferHandlerIfNecessary() {
1525 if (getTransferHandler() == null) {
1526 if (defaultTransferHandler == null) {
1527 defaultTransferHandler = new DefaultTransferHandler();
1528 }
1529 setTransferHandler(defaultTransferHandler);
1530 }
1531 }
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547 public void moveCaretPosition(int pos) {
1548 Document doc = getDocument();
1549 if (doc != null) {
1550 if (pos > doc.getLength() || pos < 0) {
1551 throw new IllegalArgumentException("bad position: " + pos);
1552 }
1553 caret.moveDot(pos);
1554 }
1555 }
1556
1557
1558
1559
1560 public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578 public void setFocusAccelerator(char aKey) {
1579 aKey = Character.toUpperCase(aKey);
1580 char old = focusAccelerator;
1581 focusAccelerator = aKey;
1582
1583
1584
1585 firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator);
1586 firePropertyChange("focusAccelerator", old, focusAccelerator);
1587 }
1588
1589
1590
1591
1592
1593
1594
1595
1596 public char getFocusAccelerator() {
1597 return focusAccelerator;
1598 }
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619 public void read(Reader in, Object desc) throws IOException {
1620 EditorKit kit = getUI().getEditorKit(this);
1621 Document doc = kit.createDefaultDocument();
1622 if (desc != null) {
1623 doc.putProperty(Document.StreamDescriptionProperty, desc);
1624 }
1625 try {
1626 kit.read(in, doc, 0);
1627 setDocument(doc);
1628 } catch (BadLocationException e) {
1629 throw new IOException(e.getMessage());
1630 }
1631 }
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641 public void write(Writer out) throws IOException {
1642 Document doc = getDocument();
1643 try {
1644 getUI().getEditorKit(this).write(out, doc, 0, doc.getLength());
1645 } catch (BadLocationException e) {
1646 throw new IOException(e.getMessage());
1647 }
1648 }
1649
1650 public void removeNotify() {
1651 super.removeNotify();
1652 if (getFocusedComponent() == this) {
1653 AppContext.getAppContext().remove(FOCUSED_COMPONENT);
1654 }
1655 }
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674 public void setCaretPosition(int position) {
1675 Document doc = getDocument();
1676 if (doc != null) {
1677 if (position > doc.getLength() || position < 0) {
1678 throw new IllegalArgumentException("bad position: " + position);
1679 }
1680 caret.setDot(position);
1681 }
1682 }
1683
1684
1685
1686
1687
1688
1689
1690
1691 @Transient
1692 public int getCaretPosition() {
1693 return caret.getDot();
1694 }
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714 public void setText(String t) {
1715 try {
1716 Document doc = getDocument();
1717 if (doc instanceof AbstractDocument) {
1718 ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
1719 }
1720 else {
1721 doc.remove(0, doc.getLength());
1722 doc.insertString(0, t, null);
1723 }
1724 } catch (BadLocationException e) {
1725 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
1726 }
1727 }
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742 public String getText() {
1743 Document doc = getDocument();
1744 String txt;
1745 try {
1746 txt = doc.getText(0, doc.getLength());
1747 } catch (BadLocationException e) {
1748 txt = null;
1749 }
1750 return txt;
1751 }
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763 public String getSelectedText() {
1764 String txt = null;
1765 int p0 = Math.min(caret.getDot(), caret.getMark());
1766 int p1 = Math.max(caret.getDot(), caret.getMark());
1767 if (p0 != p1) {
1768 try {
1769 Document doc = getDocument();
1770 txt = doc.getText(p0, p1 - p0);
1771 } catch (BadLocationException e) {
1772 throw new IllegalArgumentException(e.getMessage());
1773 }
1774 }
1775 return txt;
1776 }
1777
1778
1779
1780
1781
1782
1783
1784
1785 public boolean isEditable() {
1786 return editable;
1787 }
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801 public void setEditable(boolean b) {
1802 if (b != editable) {
1803 boolean oldVal = editable;
1804 editable = b;
1805 enableInputMethods(editable);
1806 firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable));
1807 repaint();
1808 }
1809 }
1810
1811
1812
1813
1814
1815
1816
1817 @Transient
1818 public int getSelectionStart() {
1819 int start = Math.min(caret.getDot(), caret.getMark());
1820 return start;
1821 }
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837 public void setSelectionStart(int selectionStart) {
1838
1839
1840
1841 select(selectionStart, getSelectionEnd());
1842 }
1843
1844
1845
1846
1847
1848
1849
1850 @Transient
1851 public int getSelectionEnd() {
1852 int end = Math.max(caret.getDot(), caret.getMark());
1853 return end;
1854 }
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870 public void setSelectionEnd(int selectionEnd) {
1871
1872
1873
1874 select(getSelectionStart(), selectionEnd);
1875 }
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905 public void select(int selectionStart, int selectionEnd) {
1906
1907 int docLength = getDocument().getLength();
1908
1909 if (selectionStart < 0) {
1910 selectionStart = 0;
1911 }
1912 if (selectionStart > docLength) {
1913 selectionStart = docLength;
1914 }
1915 if (selectionEnd > docLength) {
1916 selectionEnd = docLength;
1917 }
1918 if (selectionEnd < selectionStart) {
1919 selectionEnd = selectionStart;
1920 }
1921
1922 setCaretPosition(selectionStart);
1923 moveCaretPosition(selectionEnd);
1924 }
1925
1926
1927
1928
1929
1930 public void selectAll() {
1931 Document doc = getDocument();
1932 if (doc != null) {
1933 setCaretPosition(0);
1934 moveCaretPosition(doc.getLength());
1935 }
1936 }
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962 public String getToolTipText(MouseEvent event) {
1963 String retValue = super.getToolTipText(event);
1964
1965 if (retValue == null) {
1966 TextUI ui = getUI();
1967 if (ui != null) {
1968 retValue = ui.getToolTipText(this, new Point(event.getX(),
1969 event.getY()));
1970 }
1971 }
1972 return retValue;
1973 }
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985 public Dimension getPreferredScrollableViewportSize() {
1986 return getPreferredSize();
1987 }
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
2011 switch(orientation) {
2012 case SwingConstants.VERTICAL:
2013 return visibleRect.height / 10;
2014 case SwingConstants.HORIZONTAL:
2015 return visibleRect.width / 10;
2016 default:
2017 throw new IllegalArgumentException("Invalid orientation: " + orientation);
2018 }
2019 }
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
2041 switch(orientation) {
2042 case SwingConstants.VERTICAL:
2043 return visibleRect.height;
2044 case SwingConstants.HORIZONTAL:
2045 return visibleRect.width;
2046 default:
2047 throw new IllegalArgumentException("Invalid orientation: " + orientation);
2048 }
2049 }
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068 public boolean getScrollableTracksViewportWidth() {
2069 Container parent = SwingUtilities.getUnwrappedParent(this);
2070 if (parent instanceof JViewport) {
2071 return parent.getWidth() > getPreferredSize().width;
2072 }
2073 return false;
2074 }
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089 public boolean getScrollableTracksViewportHeight() {
2090 Container parent = SwingUtilities.getUnwrappedParent(this);
2091 if (parent instanceof JViewport) {
2092 return parent.getHeight() > getPreferredSize().height;
2093 }
2094 return false;
2095 }
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124 public boolean print() throws PrinterException {
2125 return print(null, null, true, null, null, true);
2126 }
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153 public boolean print(final MessageFormat headerFormat,
2154 final MessageFormat footerFormat) throws PrinterException {
2155 return print(headerFormat, footerFormat, true, null, null, true);
2156 }
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268 public boolean print(final MessageFormat headerFormat,
2269 final MessageFormat footerFormat,
2270 final boolean showPrintDialog,
2271 final PrintService service,
2272 final PrintRequestAttributeSet attributes,
2273 final boolean interactive)
2274 throws PrinterException {
2275
2276 final PrinterJob job = PrinterJob.getPrinterJob();
2277 final Printable printable;
2278 final PrintingStatus printingStatus;
2279 final boolean isHeadless = GraphicsEnvironment.isHeadless();
2280 final boolean isEventDispatchThread =
2281 SwingUtilities.isEventDispatchThread();
2282 final Printable textPrintable = getPrintable(headerFormat, footerFormat);
2283 if (interactive && ! isHeadless) {
2284 printingStatus =
2285 PrintingStatus.createPrintingStatus(this, job);
2286 printable =
2287 printingStatus.createNotificationPrintable(textPrintable);
2288 } else {
2289 printingStatus = null;
2290 printable = textPrintable;
2291 }
2292
2293 if (service != null) {
2294 job.setPrintService(service);
2295 }
2296
2297 job.setPrintable(printable);
2298
2299 final PrintRequestAttributeSet attr = (attributes == null)
2300 ? new HashPrintRequestAttributeSet()
2301 : attributes;
2302
2303 if (showPrintDialog && ! isHeadless && ! job.printDialog(attr)) {
2304 return false;
2305 }
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316 final Callable<Object> doPrint =
2317 new Callable<Object>() {
2318 public Object call() throws Exception {
2319 try {
2320 job.print(attr);
2321 } finally {
2322 if (printingStatus != null) {
2323 printingStatus.dispose();
2324 }
2325 }
2326 return null;
2327 }
2328 };
2329
2330 final FutureTask<Object> futurePrinting =
2331 new FutureTask<Object>(doPrint);
2332
2333 final Runnable runnablePrinting =
2334 new Runnable() {
2335 public void run() {
2336
2337 boolean wasEnabled = false;
2338 if (isEventDispatchThread) {
2339 if (isEnabled()) {
2340 wasEnabled = true;
2341 setEnabled(false);
2342 }
2343 } else {
2344 try {
2345 wasEnabled = SwingUtilities2.submit(
2346 new Callable<Boolean>() {
2347 public Boolean call() throws Exception {
2348 boolean rv = isEnabled();
2349 if (rv) {
2350 setEnabled(false);
2351 }
2352 return rv;
2353 }
2354 }).get();
2355 } catch (InterruptedException e) {
2356 throw new RuntimeException(e);
2357 } catch (ExecutionException e) {
2358 Throwable cause = e.getCause();
2359 if (cause instanceof Error) {
2360 throw (Error) cause;
2361 }
2362 if (cause instanceof RuntimeException) {
2363 throw (RuntimeException) cause;
2364 }
2365 throw new AssertionError(cause);
2366 }
2367 }
2368
2369 getDocument().render(futurePrinting);
2370
2371
2372 if (wasEnabled) {
2373 if (isEventDispatchThread) {
2374 setEnabled(true);
2375 } else {
2376 try {
2377 SwingUtilities2.submit(
2378 new Runnable() {
2379 public void run() {
2380 setEnabled(true);
2381 }
2382 }, null).get();
2383 } catch (InterruptedException e) {
2384 throw new RuntimeException(e);
2385 } catch (ExecutionException e) {
2386 Throwable cause = e.getCause();
2387 if (cause instanceof Error) {
2388 throw (Error) cause;
2389 }
2390 if (cause instanceof RuntimeException) {
2391 throw (RuntimeException) cause;
2392 }
2393 throw new AssertionError(cause);
2394 }
2395 }
2396 }
2397 }
2398 };
2399
2400 if (! interactive || isHeadless) {
2401 runnablePrinting.run();
2402 } else {
2403 if (isEventDispatchThread) {
2404 (new Thread(runnablePrinting)).start();
2405 printingStatus.showModal(true);
2406 } else {
2407 printingStatus.showModal(false);
2408 runnablePrinting.run();
2409 }
2410 }
2411
2412
2413
2414 try {
2415 futurePrinting.get();
2416 } catch (InterruptedException e) {
2417 throw new RuntimeException(e);
2418 } catch (ExecutionException e) {
2419 Throwable cause = e.getCause();
2420 if (cause instanceof PrinterAbortException) {
2421 if (printingStatus != null
2422 && printingStatus.isAborted()) {
2423 return false;
2424 } else {
2425 throw (PrinterAbortException) cause;
2426 }
2427 } else if (cause instanceof PrinterException) {
2428 throw (PrinterException) cause;
2429 } else if (cause instanceof RuntimeException) {
2430 throw (RuntimeException) cause;
2431 } else if (cause instanceof Error) {
2432 throw (Error) cause;
2433 } else {
2434 throw new AssertionError(cause);
2435 }
2436 }
2437 return true;
2438 }
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499 public Printable getPrintable(final MessageFormat headerFormat,
2500 final MessageFormat footerFormat) {
2501 return TextComponentPrintable.getPrintable(
2502 this, headerFormat, footerFormat);
2503 }
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523 public AccessibleContext getAccessibleContext() {
2524 if (accessibleContext == null) {
2525 accessibleContext = new AccessibleJTextComponent();
2526 }
2527 return accessibleContext;
2528 }
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544 public class AccessibleJTextComponent extends AccessibleJComponent
2545 implements AccessibleText, CaretListener, DocumentListener,
2546 AccessibleAction, AccessibleEditableText,
2547 AccessibleExtendedText {
2548
2549 int caretPos;
2550 Point oldLocationOnScreen;
2551
2552
2553
2554
2555
2556 public AccessibleJTextComponent() {
2557 Document doc = JTextComponent.this.getDocument();
2558 if (doc != null) {
2559 doc.addDocumentListener(this);
2560 }
2561 JTextComponent.this.addCaretListener(this);
2562 caretPos = getCaretPosition();
2563
2564 try {
2565 oldLocationOnScreen = getLocationOnScreen();
2566 } catch (IllegalComponentStateException iae) {
2567 }
2568
2569
2570
2571
2572
2573 JTextComponent.this.addComponentListener(new ComponentAdapter() {
2574
2575 public void componentMoved(ComponentEvent e) {
2576 try {
2577 Point newLocationOnScreen = getLocationOnScreen();
2578 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY,
2579 oldLocationOnScreen,
2580 newLocationOnScreen);
2581
2582 oldLocationOnScreen = newLocationOnScreen;
2583 } catch (IllegalComponentStateException iae) {
2584 }
2585 }
2586 });
2587 }
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598 public void caretUpdate(CaretEvent e) {
2599 int dot = e.getDot();
2600 int mark = e.getMark();
2601 if (caretPos != dot) {
2602
2603 firePropertyChange(ACCESSIBLE_CARET_PROPERTY,
2604 new Integer(caretPos), new Integer(dot));
2605 caretPos = dot;
2606
2607 try {
2608 oldLocationOnScreen = getLocationOnScreen();
2609 } catch (IllegalComponentStateException iae) {
2610 }
2611 }
2612 if (mark != dot) {
2613
2614 firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null,
2615 getSelectedText());
2616 }
2617 }
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628 public void insertUpdate(DocumentEvent e) {
2629 final Integer pos = new Integer (e.getOffset());
2630 if (SwingUtilities.isEventDispatchThread()) {
2631 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos);
2632 } else {
2633 Runnable doFire = new Runnable() {
2634 public void run() {
2635 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY,
2636 null, pos);
2637 }
2638 };
2639 SwingUtilities.invokeLater(doFire);
2640 }
2641 }
2642
2643
2644
2645
2646
2647
2648
2649
2650 public void removeUpdate(DocumentEvent e) {
2651 final Integer pos = new Integer (e.getOffset());
2652 if (SwingUtilities.isEventDispatchThread()) {
2653 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos);
2654 } else {
2655 Runnable doFire = new Runnable() {
2656 public void run() {
2657 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY,
2658 null, pos);
2659 }
2660 };
2661 SwingUtilities.invokeLater(doFire);
2662 }
2663 }
2664
2665
2666
2667
2668
2669
2670
2671
2672 public void changedUpdate(DocumentEvent e) {
2673 final Integer pos = new Integer (e.getOffset());
2674 if (SwingUtilities.isEventDispatchThread()) {
2675 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos);
2676 } else {
2677 Runnable doFire = new Runnable() {
2678 public void run() {
2679 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY,
2680 null, pos);
2681 }
2682 };
2683 SwingUtilities.invokeLater(doFire);
2684 }
2685 }
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700 public AccessibleStateSet getAccessibleStateSet() {
2701 AccessibleStateSet states = super.getAccessibleStateSet();
2702 if (JTextComponent.this.isEditable()) {
2703 states.add(AccessibleState.EDITABLE);
2704 }
2705 return states;
2706 }
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716 public AccessibleRole getAccessibleRole() {
2717 return AccessibleRole.TEXT;
2718 }
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728 public AccessibleText getAccessibleText() {
2729 return this;
2730 }
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748 public int getIndexAtPoint(Point p) {
2749 if (p == null) {
2750 return -1;
2751 }
2752 return JTextComponent.this.viewToModel(p);
2753 }
2754
2755
2756
2757
2758
2759
2760
2761
2762 Rectangle getRootEditorRect() {
2763 Rectangle alloc = JTextComponent.this.getBounds();
2764 if ((alloc.width > 0) && (alloc.height > 0)) {
2765 alloc.x = alloc.y = 0;
2766 Insets insets = JTextComponent.this.getInsets();
2767 alloc.x += insets.left;
2768 alloc.y += insets.top;
2769 alloc.width -= insets.left + insets.right;
2770 alloc.height -= insets.top + insets.bottom;
2771 return alloc;
2772 }
2773 return null;
2774 }
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804 public Rectangle getCharacterBounds(int i) {
2805 if (i < 0 || i > model.getLength()-1) {
2806 return null;
2807 }
2808 TextUI ui = getUI();
2809 if (ui == null) {
2810 return null;
2811 }
2812 Rectangle rect = null;
2813 Rectangle alloc = getRootEditorRect();
2814 if (alloc == null) {
2815 return null;
2816 }
2817 if (model instanceof AbstractDocument) {
2818 ((AbstractDocument)model).readLock();
2819 }
2820 try {
2821 View rootView = ui.getRootView(JTextComponent.this);
2822 if (rootView != null) {
2823 rootView.setSize(alloc.width, alloc.height);
2824
2825 Shape bounds = rootView.modelToView(i,
2826 Position.Bias.Forward, i+1,
2827 Position.Bias.Backward, alloc);
2828
2829 rect = (bounds instanceof Rectangle) ?
2830 (Rectangle)bounds : bounds.getBounds();
2831
2832 }
2833 } catch (BadLocationException e) {
2834 } finally {
2835 if (model instanceof AbstractDocument) {
2836 ((AbstractDocument)model).readUnlock();
2837 }
2838 }
2839 return rect;
2840 }
2841
2842
2843
2844
2845
2846
2847 public int getCharCount() {
2848 return model.getLength();
2849 }
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860 public int getCaretPosition() {
2861 return JTextComponent.this.getCaretPosition();
2862 }
2863
2864
2865
2866
2867
2868
2869
2870 public AttributeSet getCharacterAttribute(int i) {
2871 Element e = null;
2872 if (model instanceof AbstractDocument) {
2873 ((AbstractDocument)model).readLock();
2874 }
2875 try {
2876 for (e = model.getDefaultRootElement(); ! e.isLeaf(); ) {
2877 int index = e.getElementIndex(i);
2878 e = e.getElement(index);
2879 }
2880 } finally {
2881 if (model instanceof AbstractDocument) {
2882 ((AbstractDocument)model).readUnlock();
2883 }
2884 }
2885 return e.getAttributes();
2886 }
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898 public int getSelectionStart() {
2899 return JTextComponent.this.getSelectionStart();
2900 }
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911 public int getSelectionEnd() {
2912 return JTextComponent.this.getSelectionEnd();
2913 }
2914
2915
2916
2917
2918
2919
2920 public String getSelectedText() {
2921 return JTextComponent.this.getSelectedText();
2922 }
2923
2924
2925
2926
2927
2928 private class IndexedSegment extends Segment {
2929
2930
2931
2932 public int modelOffset;
2933 }
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946 public String getAtIndex(int part, int index) {
2947 return getAtIndex(part, index, 0);
2948 }
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959 public String getAfterIndex(int part, int index) {
2960 return getAtIndex(part, index, 1);
2961 }
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972 public String getBeforeIndex(int part, int index) {
2973 return getAtIndex(part, index, -1);
2974 }
2975
2976
2977
2978
2979
2980
2981
2982 private String getAtIndex(int part, int index, int direction) {
2983 if (model instanceof AbstractDocument) {
2984 ((AbstractDocument)model).readLock();
2985 }
2986 try {
2987 if (index < 0 || index >= model.getLength()) {
2988 return null;
2989 }
2990 switch (part) {
2991 case AccessibleText.CHARACTER:
2992 if (index + direction < model.getLength() &&
2993 index + direction >= 0) {
2994 return model.getText(index + direction, 1);
2995 }
2996 break;
2997
2998
2999 case AccessibleText.WORD:
3000 case AccessibleText.SENTENCE:
3001 IndexedSegment seg = getSegmentAt(part, index);
3002 if (seg != null) {
3003 if (direction != 0) {
3004 int next;
3005
3006
3007 if (direction < 0) {
3008 next = seg.modelOffset - 1;
3009 }
3010 else {
3011 next = seg.modelOffset + direction * seg.count;
3012 }
3013 if (next >= 0 && next <= model.getLength()) {
3014 seg = getSegmentAt(part, next);
3015 }
3016 else {
3017 seg = null;
3018 }
3019 }
3020 if (seg != null) {
3021 return new String(seg.array, seg.offset,
3022 seg.count);
3023 }
3024 }
3025 break;
3026
3027
3028 default:
3029 break;
3030 }
3031 } catch (BadLocationException e) {
3032 } finally {
3033 if (model instanceof AbstractDocument) {
3034 ((AbstractDocument)model).readUnlock();
3035 }
3036 }
3037 return null;
3038 }
3039
3040
3041
3042
3043
3044 private Element getParagraphElement(int index) {
3045 if (model instanceof PlainDocument ) {
3046 PlainDocument sdoc = (PlainDocument)model;
3047 return sdoc.getParagraphElement(index);
3048 } else if (model instanceof StyledDocument) {
3049 StyledDocument sdoc = (StyledDocument)model;
3050 return sdoc.getParagraphElement(index);
3051 } else {
3052 Element para;
3053 for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) {
3054 int pos = para.getElementIndex(index);
3055 para = para.getElement(pos);
3056 }
3057 if (para == null) {
3058 return null;
3059 }
3060 return para.getParentElement();
3061 }
3062 }
3063
3064
3065
3066
3067
3068
3069 private IndexedSegment getParagraphElementText(int index)
3070 throws BadLocationException {
3071 Element para = getParagraphElement(index);
3072
3073
3074 if (para != null) {
3075 IndexedSegment segment = new IndexedSegment();
3076 try {
3077 int length = para.getEndOffset() - para.getStartOffset();
3078 model.getText(para.getStartOffset(), length, segment);
3079 } catch (BadLocationException e) {
3080 return null;
3081 }
3082 segment.modelOffset = para.getStartOffset();
3083 return segment;
3084 }
3085 return null;
3086 }
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097 private IndexedSegment getSegmentAt(int part, int index) throws
3098 BadLocationException {
3099 IndexedSegment seg = getParagraphElementText(index);
3100 if (seg == null) {
3101 return null;
3102 }
3103 BreakIterator iterator;
3104 switch (part) {
3105 case AccessibleText.WORD:
3106 iterator = BreakIterator.getWordInstance(getLocale());
3107 break;
3108 case AccessibleText.SENTENCE:
3109 iterator = BreakIterator.getSentenceInstance(getLocale());
3110 break;
3111 default:
3112 return null;
3113 }
3114 seg.first();
3115 iterator.setText(seg);
3116 int end = iterator.following(index - seg.modelOffset + seg.offset);
3117 if (end == BreakIterator.DONE) {
3118 return null;
3119 }
3120 if (end > seg.offset + seg.count) {
3121 return null;
3122 }
3123 int begin = iterator.previous();
3124 if (begin == BreakIterator.DONE ||
3125 begin >= seg.offset + seg.count) {
3126 return null;
3127 }
3128 seg.modelOffset = seg.modelOffset + begin - seg.offset;
3129 seg.offset = begin;
3130 seg.count = end - begin;
3131 return seg;
3132 }
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143 public AccessibleEditableText getAccessibleEditableText() {
3144 return this;
3145 }
3146
3147
3148
3149
3150
3151
3152
3153 public void setTextContents(String s) {
3154 JTextComponent.this.setText(s);
3155 }
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165 public void insertTextAtIndex(int index, String s) {
3166 Document doc = JTextComponent.this.getDocument();
3167 if (doc != null) {
3168 try {
3169 if (s != null && s.length() > 0) {
3170 boolean composedTextSaved = saveComposedText(index);
3171 doc.insertString(index, s, null);
3172 if (composedTextSaved) {
3173 restoreComposedText();
3174 }
3175 }
3176 } catch (BadLocationException e) {
3177 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
3178 }
3179 }
3180 }
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190 public String getTextRange(int startIndex, int endIndex) {
3191 String txt = null;
3192 int p0 = Math.min(startIndex, endIndex);
3193 int p1 = Math.max(startIndex, endIndex);
3194 if (p0 != p1) {
3195 try {
3196 Document doc = JTextComponent.this.getDocument();
3197 txt = doc.getText(p0, p1 - p0);
3198 } catch (BadLocationException e) {
3199 throw new IllegalArgumentException(e.getMessage());
3200 }
3201 }
3202 return txt;
3203 }
3204
3205
3206
3207
3208
3209
3210
3211
3212 public void delete(int startIndex, int endIndex) {
3213 if (isEditable() && isEnabled()) {
3214 try {
3215 int p0 = Math.min(startIndex, endIndex);
3216 int p1 = Math.max(startIndex, endIndex);
3217 if (p0 != p1) {
3218 Document doc = getDocument();
3219 doc.remove(p0, p1 - p0);
3220 }
3221 } catch (BadLocationException e) {
3222 }
3223 } else {
3224 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
3225 }
3226 }
3227
3228
3229
3230
3231
3232
3233
3234
3235 public void cut(int startIndex, int endIndex) {
3236 selectText(startIndex, endIndex);
3237 JTextComponent.this.cut();
3238 }
3239
3240
3241
3242
3243
3244
3245
3246
3247 public void paste(int startIndex) {
3248 setCaretPosition(startIndex);
3249 JTextComponent.this.paste();
3250 }
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261 public void replaceText(int startIndex, int endIndex, String s) {
3262 selectText(startIndex, endIndex);
3263 JTextComponent.this.replaceSelection(s);
3264 }
3265
3266
3267
3268
3269
3270
3271
3272
3273 public void selectText(int startIndex, int endIndex) {
3274 JTextComponent.this.select(startIndex, endIndex);
3275 }
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286 public void setAttributes(int startIndex, int endIndex,
3287 AttributeSet as) {
3288
3289
3290 Document doc = JTextComponent.this.getDocument();
3291 if (doc != null && doc instanceof StyledDocument) {
3292 StyledDocument sDoc = (StyledDocument)doc;
3293 int offset = startIndex;
3294 int length = endIndex - startIndex;
3295 sDoc.setCharacterAttributes(offset, length, as, true);
3296 }
3297 }
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331 private AccessibleTextSequence getSequenceAtIndex(int part,
3332 int index, int direction) {
3333 if (index < 0 || index >= model.getLength()) {
3334 return null;
3335 }
3336 if (direction < -1 || direction > 1) {
3337 return null;
3338 }
3339
3340 switch (part) {
3341 case AccessibleText.CHARACTER:
3342 if (model instanceof AbstractDocument) {
3343 ((AbstractDocument)model).readLock();
3344 }
3345 AccessibleTextSequence charSequence = null;
3346 try {
3347 if (index + direction < model.getLength() &&
3348 index + direction >= 0) {
3349 charSequence =
3350 new AccessibleTextSequence(index + direction,
3351 index + direction + 1,
3352 model.getText(index + direction, 1));
3353 }
3354
3355 } catch (BadLocationException e) {
3356
3357
3358 } finally {
3359 if (model instanceof AbstractDocument) {
3360 ((AbstractDocument)model).readUnlock();
3361 }
3362 }
3363 return charSequence;
3364
3365 case AccessibleText.WORD:
3366 case AccessibleText.SENTENCE:
3367 if (model instanceof AbstractDocument) {
3368 ((AbstractDocument)model).readLock();
3369 }
3370 AccessibleTextSequence rangeSequence = null;
3371 try {
3372 IndexedSegment seg = getSegmentAt(part, index);
3373 if (seg != null) {
3374 if (direction != 0) {
3375 int next;
3376
3377 if (direction < 0) {
3378 next = seg.modelOffset - 1;
3379 }
3380 else {
3381 next = seg.modelOffset + seg.count;
3382 }
3383 if (next >= 0 && next <= model.getLength()) {
3384 seg = getSegmentAt(part, next);
3385 }
3386 else {
3387 seg = null;
3388 }
3389 }
3390 if (seg != null &&
3391 (seg.offset + seg.count) <= model.getLength()) {
3392 rangeSequence =
3393 new AccessibleTextSequence (seg.offset,
3394 seg.offset + seg.count,
3395 new String(seg.array, seg.offset, seg.count));
3396 }
3397 }
3398 } catch(BadLocationException e) {
3399
3400
3401 } finally {
3402 if (model instanceof AbstractDocument) {
3403 ((AbstractDocument)model).readUnlock();
3404 }
3405 }
3406 return rangeSequence;
3407
3408 case AccessibleExtendedText.LINE:
3409 AccessibleTextSequence lineSequence = null;
3410 if (model instanceof AbstractDocument) {
3411 ((AbstractDocument)model).readLock();
3412 }
3413 try {
3414 int startIndex =
3415 Utilities.getRowStart(JTextComponent.this, index);
3416 int endIndex =
3417 Utilities.getRowEnd(JTextComponent.this, index);
3418 if (startIndex >= 0 && endIndex >= startIndex) {
3419 if (direction == 0) {
3420 lineSequence =
3421 new AccessibleTextSequence(startIndex, endIndex,
3422 model.getText(startIndex,
3423 endIndex - startIndex + 1));
3424 } else if (direction == -1 && startIndex > 0) {
3425 endIndex =
3426 Utilities.getRowEnd(JTextComponent.this,
3427 startIndex - 1);
3428 startIndex =
3429 Utilities.getRowStart(JTextComponent.this,
3430 startIndex - 1);
3431 if (startIndex >= 0 && endIndex >= startIndex) {
3432 lineSequence =
3433 new AccessibleTextSequence(startIndex,
3434 endIndex,
3435 model.getText(startIndex,
3436 endIndex - startIndex + 1));
3437 }
3438 } else if (direction == 1 &&
3439 endIndex < model.getLength()) {
3440 startIndex =
3441 Utilities.getRowStart(JTextComponent.this,
3442 endIndex + 1);
3443 endIndex =
3444 Utilities.getRowEnd(JTextComponent.this,
3445 endIndex + 1);
3446 if (startIndex >= 0 && endIndex >= startIndex) {
3447 lineSequence =
3448 new AccessibleTextSequence(startIndex,
3449 endIndex, model.getText(startIndex,
3450 endIndex - startIndex + 1));
3451 }
3452 }
3453
3454 }
3455 } catch(BadLocationException e) {
3456
3457
3458 } finally {
3459 if (model instanceof AbstractDocument) {
3460 ((AbstractDocument)model).readUnlock();
3461 }
3462 }
3463 return lineSequence;
3464
3465 case AccessibleExtendedText.ATTRIBUTE_RUN:
3466
3467
3468
3469
3470 int attributeRunStartIndex, attributeRunEndIndex;
3471 String runText = null;
3472 if (model instanceof AbstractDocument) {
3473 ((AbstractDocument)model).readLock();
3474 }
3475
3476 try {
3477 attributeRunStartIndex = attributeRunEndIndex =
3478 Integer.MIN_VALUE;
3479 int tempIndex = index;
3480 switch (direction) {
3481 case -1:
3482
3483
3484
3485 attributeRunEndIndex = getRunEdge(index, direction);
3486
3487
3488 tempIndex = attributeRunEndIndex - 1;
3489 break;
3490 case 1:
3491
3492
3493
3494 attributeRunStartIndex = getRunEdge(index, direction);
3495
3496
3497 tempIndex = attributeRunStartIndex;
3498 break;
3499 case 0:
3500
3501
3502 break;
3503 default:
3504
3505 throw new AssertionError(direction);
3506 }
3507
3508
3509
3510 attributeRunStartIndex =
3511 (attributeRunStartIndex != Integer.MIN_VALUE) ?
3512 attributeRunStartIndex : getRunEdge(tempIndex, -1);
3513 attributeRunEndIndex =
3514 (attributeRunEndIndex != Integer.MIN_VALUE) ?
3515 attributeRunEndIndex : getRunEdge(tempIndex, 1);
3516
3517 runText = model.getText(attributeRunStartIndex,
3518 attributeRunEndIndex -
3519 attributeRunStartIndex);
3520 } catch (BadLocationException e) {
3521
3522
3523 return null;
3524 } finally {
3525 if (model instanceof AbstractDocument) {
3526 ((AbstractDocument)model).readUnlock();
3527 }
3528 }
3529 return new AccessibleTextSequence(attributeRunStartIndex,
3530 attributeRunEndIndex,
3531 runText);
3532
3533 default:
3534 break;
3535 }
3536 return null;
3537 }
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548 private int getRunEdge(int index, int direction) throws
3549 BadLocationException {
3550 if (index < 0 || index >= model.getLength()) {
3551 throw new BadLocationException("Location out of bounds", index);
3552 }
3553
3554 Element indexElement;
3555
3556 int elementIndex = -1;
3557 for (indexElement = model.getDefaultRootElement();
3558 ! indexElement.isLeaf(); ) {
3559 elementIndex = indexElement.getElementIndex(index);
3560 indexElement = indexElement.getElement(elementIndex);
3561 }
3562 if (elementIndex == -1) {
3563 throw new AssertionError(index);
3564 }
3565
3566 AttributeSet indexAS = indexElement.getAttributes();
3567 Element parent = indexElement.getParentElement();
3568
3569
3570
3571
3572 Element edgeElement;
3573 switch (direction) {
3574 case -1:
3575 case 1:
3576 int edgeElementIndex = elementIndex;
3577 int elementCount = parent.getElementCount();
3578 while ((edgeElementIndex + direction) > 0 &&
3579 ((edgeElementIndex + direction) < elementCount) &&
3580 parent.getElement(edgeElementIndex
3581 + direction).getAttributes().isEqual(indexAS)) {
3582 edgeElementIndex += direction;
3583 }
3584 edgeElement = parent.getElement(edgeElementIndex);
3585 break;
3586 default:
3587 throw new AssertionError(direction);
3588 }
3589 switch (direction) {
3590 case -1:
3591 return edgeElement.getStartOffset();
3592 case 1:
3593 return edgeElement.getEndOffset();
3594 default:
3595
3596
3597 return Integer.MIN_VALUE;
3598 }
3599 }
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623 public AccessibleTextSequence getTextSequenceAt(int part, int index) {
3624 return getSequenceAtIndex(part, index, 0);
3625 }
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647 public AccessibleTextSequence getTextSequenceAfter(int part, int index) {
3648 return getSequenceAtIndex(part, index, 1);
3649 }
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671 public AccessibleTextSequence getTextSequenceBefore(int part, int index) {
3672 return getSequenceAtIndex(part, index, -1);
3673 }
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686 public Rectangle getTextBounds(int startIndex, int endIndex) {
3687 if (startIndex < 0 || startIndex > model.getLength()-1 ||
3688 endIndex < 0 || endIndex > model.getLength()-1 ||
3689 startIndex > endIndex) {
3690 return null;
3691 }
3692 TextUI ui = getUI();
3693 if (ui == null) {
3694 return null;
3695 }
3696 Rectangle rect = null;
3697 Rectangle alloc = getRootEditorRect();
3698 if (alloc == null) {
3699 return null;
3700 }
3701 if (model instanceof AbstractDocument) {
3702 ((AbstractDocument)model).readLock();
3703 }
3704 try {
3705 View rootView = ui.getRootView(JTextComponent.this);
3706 if (rootView != null) {
3707 Shape bounds = rootView.modelToView(startIndex,
3708 Position.Bias.Forward, endIndex,
3709 Position.Bias.Backward, alloc);
3710
3711 rect = (bounds instanceof Rectangle) ?
3712 (Rectangle)bounds : bounds.getBounds();
3713
3714 }
3715 } catch (BadLocationException e) {
3716 } finally {
3717 if (model instanceof AbstractDocument) {
3718 ((AbstractDocument)model).readUnlock();
3719 }
3720 }
3721 return rect;
3722 }
3723
3724
3725
3726
3727
3728
3729 public AccessibleAction getAccessibleAction() {
3730 return this;
3731 }
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741 public int getAccessibleActionCount() {
3742 Action [] actions = JTextComponent.this.getActions();
3743 return actions.length;
3744 }
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754 public String getAccessibleActionDescription(int i) {
3755 Action [] actions = JTextComponent.this.getActions();
3756 if (i < 0 || i >= actions.length) {
3757 return null;
3758 }
3759 return (String)actions[i].getValue(Action.NAME);
3760 }
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770 public boolean doAccessibleAction(int i) {
3771 Action [] actions = JTextComponent.this.getActions();
3772 if (i < 0 || i >= actions.length) {
3773 return false;
3774 }
3775 ActionEvent ae =
3776 new ActionEvent(JTextComponent.this,
3777 ActionEvent.ACTION_PERFORMED, null,
3778 EventQueue.getMostRecentEventTime(),
3779 getCurrentEventModifiers());
3780 actions[i].actionPerformed(ae);
3781 return true;
3782 }
3783
3784
3785
3786
3787 }
3788
3789
3790
3791
3792 private void readObject(ObjectInputStream s)
3793 throws IOException, ClassNotFoundException
3794 {
3795 s.defaultReadObject();
3796 caretEvent = new MutableCaretEvent(this);
3797 addMouseListener(caretEvent);
3798 addFocusListener(caretEvent);
3799 }
3800
3801
3802
3803
3804
3805
3806 private Document model;
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816 private transient Caret caret;
3817
3818
3819
3820
3821 private NavigationFilter navigationFilter;
3822
3823
3824
3825
3826
3827
3828
3829
3830 private transient Highlighter highlighter;
3831
3832
3833
3834
3835
3836
3837
3838
3839 private transient Keymap keymap;
3840
3841 private transient MutableCaretEvent caretEvent;
3842 private Color caretColor;
3843 private Color selectionColor;
3844 private Color selectedTextColor;
3845 private Color disabledTextColor;
3846 private boolean editable;
3847 private Insets margin;
3848 private char focusAccelerator;
3849 private boolean dragEnabled;
3850
3851
3852
3853
3854 private DropMode dropMode = DropMode.USE_SELECTION;
3855
3856
3857
3858
3859 private transient DropLocation dropLocation;
3860
3861
3862
3863
3864
3865
3866
3867 public static final class DropLocation extends TransferHandler.DropLocation {
3868 private final int index;
3869 private final Position.Bias bias;
3870
3871 private DropLocation(Point p, int index, Position.Bias bias) {
3872 super(p);
3873 this.index = index;
3874 this.bias = bias;
3875 }
3876
3877
3878
3879
3880
3881
3882
3883
3884 public int getIndex() {
3885 return index;
3886 }
3887
3888
3889
3890
3891
3892
3893 public Position.Bias getBias() {
3894 return bias;
3895 }
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905 public String toString() {
3906 return getClass().getName()
3907 + "[dropPoint=" + getDropPoint() + ","
3908 + "index=" + index + ","
3909 + "bias=" + bias + "]";
3910 }
3911 }
3912
3913
3914
3915
3916 private static DefaultTransferHandler defaultTransferHandler;
3917
3918
3919
3920
3921
3922 private static Map<String, Boolean> overrideMap;
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936 protected String paramString() {
3937 String editableString = (editable ?
3938 "true" : "false");
3939 String caretColorString = (caretColor != null ?
3940 caretColor.toString() : "");
3941 String selectionColorString = (selectionColor != null ?
3942 selectionColor.toString() : "");
3943 String selectedTextColorString = (selectedTextColor != null ?
3944 selectedTextColor.toString() : "");
3945 String disabledTextColorString = (disabledTextColor != null ?
3946 disabledTextColor.toString() : "");
3947 String marginString = (margin != null ?
3948 margin.toString() : "");
3949
3950 return super.paramString() +
3951 ",caretColor=" + caretColorString +
3952 ",disabledTextColor=" + disabledTextColorString +
3953 ",editable=" + editableString +
3954 ",margin=" + marginString +
3955 ",selectedTextColor=" + selectedTextColorString +
3956 ",selectionColor=" + selectionColorString;
3957 }
3958
3959
3960
3961
3962
3963
3964
3965
3966 static class DefaultTransferHandler extends TransferHandler implements
3967 UIResource {
3968 public void exportToClipboard(JComponent comp, Clipboard clipboard,
3969 int action) throws IllegalStateException {
3970 if (comp instanceof JTextComponent) {
3971 JTextComponent text = (JTextComponent)comp;
3972 int p0 = text.getSelectionStart();
3973 int p1 = text.getSelectionEnd();
3974 if (p0 != p1) {
3975 try {
3976 Document doc = text.getDocument();
3977 String srcData = doc.getText(p0, p1 - p0);
3978 StringSelection contents =new StringSelection(srcData);
3979
3980
3981
3982
3983 clipboard.setContents(contents, null);
3984
3985 if (action == TransferHandler.MOVE) {
3986 doc.remove(p0, p1 - p0);
3987 }
3988 } catch (BadLocationException ble) {}
3989 }
3990 }
3991 }
3992 public boolean importData(JComponent comp, Transferable t) {
3993 if (comp instanceof JTextComponent) {
3994 DataFlavor flavor = getFlavor(t.getTransferDataFlavors());
3995
3996 if (flavor != null) {
3997 InputContext ic = comp.getInputContext();
3998 if (ic != null) {
3999 ic.endComposition();
4000 }
4001 try {
4002 String data = (String)t.getTransferData(flavor);
4003
4004 ((JTextComponent)comp).replaceSelection(data);
4005 return true;
4006 } catch (UnsupportedFlavorException ufe) {
4007 } catch (IOException ioe) {
4008 }
4009 }
4010 }
4011 return false;
4012 }
4013 public boolean canImport(JComponent comp,
4014 DataFlavor[] transferFlavors) {
4015 JTextComponent c = (JTextComponent)comp;
4016 if (!(c.isEditable() && c.isEnabled())) {
4017 return false;
4018 }
4019 return (getFlavor(transferFlavors) != null);
4020 }
4021 public int getSourceActions(JComponent c) {
4022 return NONE;
4023 }
4024 private DataFlavor getFlavor(DataFlavor[] flavors) {
4025 if (flavors != null) {
4026 for (DataFlavor flavor : flavors) {
4027 if (flavor.equals(DataFlavor.stringFlavor)) {
4028 return flavor;
4029 }
4030 }
4031 }
4032 return null;
4033 }
4034 }
4035
4036
4037
4038
4039
4040 static final JTextComponent getFocusedComponent() {
4041 return (JTextComponent)AppContext.getAppContext().
4042 get(FOCUSED_COMPONENT);
4043 }
4044
4045 private int getCurrentEventModifiers() {
4046 int modifiers = 0;
4047 AWTEvent currentEvent = EventQueue.getCurrentEvent();
4048 if (currentEvent instanceof InputEvent) {
4049 modifiers = ((InputEvent)currentEvent).getModifiers();
4050 } else if (currentEvent instanceof ActionEvent) {
4051 modifiers = ((ActionEvent)currentEvent).getModifiers();
4052 }
4053 return modifiers;
4054 }
4055
4056 private static final Object KEYMAP_TABLE =
4057 new StringBuilder("JTextComponent_KeymapTable");
4058
4059
4060
4061
4062
4063 private transient InputMethodRequests inputMethodRequestsHandler;
4064 private SimpleAttributeSet composedTextAttribute;
4065 private String composedTextContent;
4066 private Position composedTextStart;
4067 private Position composedTextEnd;
4068 private Position latestCommittedTextStart;
4069 private Position latestCommittedTextEnd;
4070 private ComposedTextCaret composedTextCaret;
4071 private transient Caret originalCaret;
4072
4073
4074
4075
4076 private boolean checkedInputOverride;
4077 private boolean needToSendKeyTypedEvent;
4078
4079 static class DefaultKeymap implements Keymap {
4080
4081 DefaultKeymap(String nm, Keymap parent) {
4082 this.nm = nm;
4083 this.parent = parent;
4084 bindings = new Hashtable<KeyStroke, Action>();
4085 }
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095 public Action getDefaultAction() {
4096 if (defaultAction != null) {
4097 return defaultAction;
4098 }
4099 return (parent != null) ? parent.getDefaultAction() : null;
4100 }
4101
4102
4103
4104
4105 public void setDefaultAction(Action a) {
4106 defaultAction = a;
4107 }
4108
4109 public String getName() {
4110 return nm;
4111 }
4112
4113 public Action getAction(KeyStroke key) {
4114 Action a = bindings.get(key);
4115 if ((a == null) && (parent != null)) {
4116 a = parent.getAction(key);
4117 }
4118 return a;
4119 }
4120
4121 public KeyStroke[] getBoundKeyStrokes() {
4122 KeyStroke[] keys = new KeyStroke[bindings.size()];
4123 int i = 0;
4124 for (Enumeration<KeyStroke> e = bindings.keys() ; e.hasMoreElements() ;) {
4125 keys[i++] = e.nextElement();
4126 }
4127 return keys;
4128 }
4129
4130 public Action[] getBoundActions() {
4131 Action[] actions = new Action[bindings.size()];
4132 int i = 0;
4133 for (Enumeration<Action> e = bindings.elements() ; e.hasMoreElements() ;) {
4134 actions[i++] = e.nextElement();
4135 }
4136 return actions;
4137 }
4138
4139 public KeyStroke[] getKeyStrokesForAction(Action a) {
4140 if (a == null) {
4141 return null;
4142 }
4143 KeyStroke[] retValue = null;
4144
4145 Vector<KeyStroke> keyStrokes = null;
4146 for (Enumeration<KeyStroke> keys = bindings.keys(); keys.hasMoreElements();) {
4147 KeyStroke key = keys.nextElement();
4148 if (bindings.get(key) == a) {
4149 if (keyStrokes == null) {
4150 keyStrokes = new Vector<KeyStroke>();
4151 }
4152 keyStrokes.addElement(key);
4153 }
4154 }
4155
4156 if (parent != null) {
4157 KeyStroke[] pStrokes = parent.getKeyStrokesForAction(a);
4158 if (pStrokes != null) {
4159
4160
4161 int rCount = 0;
4162 for (int counter = pStrokes.length - 1; counter >= 0;
4163 counter--) {
4164 if (isLocallyDefined(pStrokes[counter])) {
4165 pStrokes[counter] = null;
4166 rCount++;
4167 }
4168 }
4169 if (rCount > 0 && rCount < pStrokes.length) {
4170 if (keyStrokes == null) {
4171 keyStrokes = new Vector<KeyStroke>();
4172 }
4173 for (int counter = pStrokes.length - 1; counter >= 0;
4174 counter--) {
4175 if (pStrokes[counter] != null) {
4176 keyStrokes.addElement(pStrokes[counter]);
4177 }
4178 }
4179 }
4180 else if (rCount == 0) {
4181 if (keyStrokes == null) {
4182 retValue = pStrokes;
4183 }
4184 else {
4185 retValue = new KeyStroke[keyStrokes.size() +
4186 pStrokes.length];
4187 keyStrokes.copyInto(retValue);
4188 System.arraycopy(pStrokes, 0, retValue,
4189 keyStrokes.size(), pStrokes.length);
4190 keyStrokes = null;
4191 }
4192 }
4193 }
4194 }
4195 if (keyStrokes != null) {
4196 retValue = new KeyStroke[keyStrokes.size()];
4197 keyStrokes.copyInto(retValue);
4198 }
4199 return retValue;
4200 }
4201
4202 public boolean isLocallyDefined(KeyStroke key) {
4203 return bindings.containsKey(key);
4204 }
4205
4206 public void addActionForKeyStroke(KeyStroke key, Action a) {
4207 bindings.put(key, a);
4208 }
4209
4210 public void removeKeyStrokeBinding(KeyStroke key) {
4211 bindings.remove(key);
4212 }
4213
4214 public void removeBindings() {
4215 bindings.clear();
4216 }
4217
4218 public Keymap getResolveParent() {
4219 return parent;
4220 }
4221
4222 public void setResolveParent(Keymap parent) {
4223 this.parent = parent;
4224 }
4225
4226
4227
4228
4229
4230 public String toString() {
4231 return "Keymap[" + nm + "]" + bindings;
4232 }
4233
4234 String nm;
4235 Keymap parent;
4236 Hashtable<KeyStroke, Action> bindings;
4237 Action defaultAction;
4238 }
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256 static class KeymapWrapper extends InputMap {
4257 static final Object DefaultActionKey = new Object();
4258
4259 private Keymap keymap;
4260
4261 KeymapWrapper(Keymap keymap) {
4262 this.keymap = keymap;
4263 }
4264
4265 public KeyStroke[] keys() {
4266 KeyStroke[] sKeys = super.keys();
4267 KeyStroke[] keymapKeys = keymap.getBoundKeyStrokes();
4268 int sCount = (sKeys == null) ? 0 : sKeys.length;
4269 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length;
4270 if (sCount == 0) {
4271 return keymapKeys;
4272 }
4273 if (keymapCount == 0) {
4274 return sKeys;
4275 }
4276 KeyStroke[] retValue = new KeyStroke[sCount + keymapCount];
4277
4278 System.arraycopy(sKeys, 0, retValue, 0, sCount);
4279 System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount);
4280 return retValue;
4281 }
4282
4283 public int size() {
4284
4285 KeyStroke[] keymapStrokes = keymap.getBoundKeyStrokes();
4286 int keymapCount = (keymapStrokes == null) ? 0:
4287 keymapStrokes.length;
4288 return super.size() + keymapCount;
4289 }
4290
4291 public Object get(KeyStroke keyStroke) {
4292 Object retValue = keymap.getAction(keyStroke);
4293 if (retValue == null) {
4294 retValue = super.get(keyStroke);
4295 if (retValue == null &&
4296 keyStroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED &&
4297 keymap.getDefaultAction() != null) {
4298
4299
4300 retValue = DefaultActionKey;
4301 }
4302 }
4303 return retValue;
4304 }
4305 }
4306
4307
4308
4309
4310
4311
4312
4313
4314 static class KeymapActionMap extends ActionMap {
4315 private Keymap keymap;
4316
4317 KeymapActionMap(Keymap keymap) {
4318 this.keymap = keymap;
4319 }
4320
4321 public Object[] keys() {
4322 Object[] sKeys = super.keys();
4323 Object[] keymapKeys = keymap.getBoundActions();
4324 int sCount = (sKeys == null) ? 0 : sKeys.length;
4325 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length;
4326 boolean hasDefault = (keymap.getDefaultAction() != null);
4327 if (hasDefault) {
4328 keymapCount++;
4329 }
4330 if (sCount == 0) {
4331 if (hasDefault) {
4332 Object[] retValue = new Object[keymapCount];
4333 if (keymapCount > 1) {
4334 System.arraycopy(keymapKeys, 0, retValue, 0,
4335 keymapCount - 1);
4336 }
4337 retValue[keymapCount - 1] = KeymapWrapper.DefaultActionKey;
4338 return retValue;
4339 }
4340 return keymapKeys;
4341 }
4342 if (keymapCount == 0) {
4343 return sKeys;
4344 }
4345 Object[] retValue = new Object[sCount + keymapCount];
4346
4347 System.arraycopy(sKeys, 0, retValue, 0, sCount);
4348 if (hasDefault) {
4349 if (keymapCount > 1) {
4350 System.arraycopy(keymapKeys, 0, retValue, sCount,
4351 keymapCount - 1);
4352 }
4353 retValue[sCount + keymapCount - 1] = KeymapWrapper.
4354 DefaultActionKey;
4355 }
4356 else {
4357 System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount);
4358 }
4359 return retValue;
4360 }
4361
4362 public int size() {
4363
4364 Object[] actions = keymap.getBoundActions();
4365 int keymapCount = (actions == null) ? 0 : actions.length;
4366 if (keymap.getDefaultAction() != null) {
4367 keymapCount++;
4368 }
4369 return super.size() + keymapCount;
4370 }
4371
4372 public Action get(Object key) {
4373 Action retValue = super.get(key);
4374 if (retValue == null) {
4375
4376 if (key == KeymapWrapper.DefaultActionKey) {
4377 retValue = keymap.getDefaultAction();
4378 }
4379 else if (key instanceof Action) {
4380
4381
4382
4383 retValue = (Action)key;
4384 }
4385 }
4386 return retValue;
4387 }
4388 }
4389
4390 private static final Object FOCUSED_COMPONENT =
4391 new StringBuilder("JTextComponent_FocusedComponent");
4392
4393
4394
4395
4396
4397
4398 public static final String DEFAULT_KEYMAP = "default";
4399
4400
4401
4402
4403
4404
4405 static class MutableCaretEvent extends CaretEvent implements ChangeListener, FocusListener, MouseListener {
4406
4407 MutableCaretEvent(JTextComponent c) {
4408 super(c);
4409 }
4410
4411 final void fire() {
4412 JTextComponent c = (JTextComponent) getSource();
4413 if (c != null) {
4414 Caret caret = c.getCaret();
4415 dot = caret.getDot();
4416 mark = caret.getMark();
4417 c.fireCaretUpdate(this);
4418 }
4419 }
4420
4421 public final String toString() {
4422 return "dot=" + dot + "," + "mark=" + mark;
4423 }
4424
4425
4426
4427 public final int getDot() {
4428 return dot;
4429 }
4430
4431 public final int getMark() {
4432 return mark;
4433 }
4434
4435
4436
4437 public final void stateChanged(ChangeEvent e) {
4438 if (! dragActive) {
4439 fire();
4440 }
4441 }
4442
4443
4444 public void focusGained(FocusEvent fe) {
4445 AppContext.getAppContext().put(FOCUSED_COMPONENT,
4446 fe.getSource());
4447 }
4448
4449 public void focusLost(FocusEvent fe) {
4450 }
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461 public final void mousePressed(MouseEvent e) {
4462 dragActive = true;
4463 }
4464
4465
4466
4467
4468
4469
4470
4471 public final void mouseReleased(MouseEvent e) {
4472 dragActive = false;
4473 fire();
4474 }
4475
4476 public final void mouseClicked(MouseEvent e) {
4477 }
4478
4479 public final void mouseEntered(MouseEvent e) {
4480 }
4481
4482 public final void mouseExited(MouseEvent e) {
4483 }
4484
4485 private boolean dragActive;
4486 private int dot;
4487 private int mark;
4488 }
4489
4490
4491
4492
4493
4494
4495
4496 protected void processInputMethodEvent(InputMethodEvent e) {
4497
4498 super.processInputMethodEvent(e);
4499
4500 if (!e.isConsumed()) {
4501 if (! isEditable()) {
4502 return;
4503 } else {
4504 switch (e.getID()) {
4505 case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
4506 replaceInputMethodText(e);
4507
4508
4509
4510 case InputMethodEvent.CARET_POSITION_CHANGED:
4511 setInputMethodCaretPosition(e);
4512 break;
4513 }
4514 }
4515
4516 e.consume();
4517 }
4518 }
4519
4520
4521
4522
4523 public InputMethodRequests getInputMethodRequests() {
4524 if (inputMethodRequestsHandler == null) {
4525 inputMethodRequestsHandler = new InputMethodRequestsHandler();
4526 Document doc = getDocument();
4527 if (doc != null) {
4528 doc.addDocumentListener((DocumentListener)inputMethodRequestsHandler);
4529 }
4530 }
4531
4532 return inputMethodRequestsHandler;
4533 }
4534
4535
4536
4537
4538 public void addInputMethodListener(InputMethodListener l) {
4539 super.addInputMethodListener(l);
4540 if (l != null) {
4541 needToSendKeyTypedEvent = false;
4542 checkedInputOverride = true;
4543 }
4544 }
4545
4546
4547
4548
4549
4550 class InputMethodRequestsHandler implements InputMethodRequests, DocumentListener {
4551
4552
4553
4554 public AttributedCharacterIterator cancelLatestCommittedText(
4555 Attribute[] attributes) {
4556 Document doc = getDocument();
4557 if ((doc != null) && (latestCommittedTextStart != null)
4558 && (!latestCommittedTextStart.equals(latestCommittedTextEnd))) {
4559 try {
4560 int startIndex = latestCommittedTextStart.getOffset();
4561 int endIndex = latestCommittedTextEnd.getOffset();
4562 String latestCommittedText =
4563 doc.getText(startIndex, endIndex - startIndex);
4564 doc.remove(startIndex, endIndex - startIndex);
4565 return new AttributedString(latestCommittedText).getIterator();
4566 } catch (BadLocationException ble) {}
4567 }
4568 return null;
4569 }
4570
4571 public AttributedCharacterIterator getCommittedText(int beginIndex,
4572 int endIndex, Attribute[] attributes) {
4573 int composedStartIndex = 0;
4574 int composedEndIndex = 0;
4575 if (composedTextExists()) {
4576 composedStartIndex = composedTextStart.getOffset();
4577 composedEndIndex = composedTextEnd.getOffset();
4578 }
4579
4580 String committed;
4581 try {
4582 if (beginIndex < composedStartIndex) {
4583 if (endIndex <= composedStartIndex) {
4584 committed = getText(beginIndex, endIndex - beginIndex);
4585 } else {
4586 int firstPartLength = composedStartIndex - beginIndex;
4587 committed = getText(beginIndex, firstPartLength) +
4588 getText(composedEndIndex, endIndex - beginIndex - firstPartLength);
4589 }
4590 } else {
4591 committed = getText(beginIndex + (composedEndIndex - composedStartIndex),
4592 endIndex - beginIndex);
4593 }
4594 } catch (BadLocationException ble) {
4595 throw new IllegalArgumentException("Invalid range");
4596 }
4597 return new AttributedString(committed).getIterator();
4598 }
4599
4600 public int getCommittedTextLength() {
4601 Document doc = getDocument();
4602 int length = 0;
4603 if (doc != null) {
4604 length = doc.getLength();
4605 if (composedTextContent != null) {
4606 if (composedTextEnd == null
4607 || composedTextStart == null) {
4608
4609
4610
4611
4612
4613
4614
4615 length -= composedTextContent.length();
4616 } else {
4617 length -= composedTextEnd.getOffset() -
4618 composedTextStart.getOffset();
4619 }
4620 }
4621 }
4622 return length;
4623 }
4624
4625 public int getInsertPositionOffset() {
4626 int composedStartIndex = 0;
4627 int composedEndIndex = 0;
4628 if (composedTextExists()) {
4629 composedStartIndex = composedTextStart.getOffset();
4630 composedEndIndex = composedTextEnd.getOffset();
4631 }
4632 int caretIndex = getCaretPosition();
4633
4634 if (caretIndex < composedStartIndex) {
4635 return caretIndex;
4636 } else if (caretIndex < composedEndIndex) {
4637 return composedStartIndex;
4638 } else {
4639 return caretIndex - (composedEndIndex - composedStartIndex);
4640 }
4641 }
4642
4643 public TextHitInfo getLocationOffset(int x, int y) {
4644 if (composedTextAttribute == null) {
4645 return null;
4646 } else {
4647 Point p = getLocationOnScreen();
4648 p.x = x - p.x;
4649 p.y = y - p.y;
4650 int pos = viewToModel(p);
4651 if ((pos >= composedTextStart.getOffset()) &&
4652 (pos <= composedTextEnd.getOffset())) {
4653 return TextHitInfo.leading(pos - composedTextStart.getOffset());
4654 } else {
4655 return null;
4656 }
4657 }
4658 }
4659
4660 public Rectangle getTextLocation(TextHitInfo offset) {
4661 Rectangle r;
4662
4663 try {
4664 r = modelToView(getCaretPosition());
4665 if (r != null) {
4666 Point p = getLocationOnScreen();
4667 r.translate(p.x, p.y);
4668 }
4669 } catch (BadLocationException ble) {
4670 r = null;
4671 }
4672
4673 if (r == null)
4674 r = new Rectangle();
4675
4676 return r;
4677 }
4678
4679 public AttributedCharacterIterator getSelectedText(
4680 Attribute[] attributes) {
4681 String selection = JTextComponent.this.getSelectedText();
4682 if (selection != null) {
4683 return new AttributedString(selection).getIterator();
4684 } else {
4685 return null;
4686 }
4687 }
4688
4689
4690
4691 public void changedUpdate(DocumentEvent e) {
4692 latestCommittedTextStart = latestCommittedTextEnd = null;
4693 }
4694
4695 public void insertUpdate(DocumentEvent e) {
4696 latestCommittedTextStart = latestCommittedTextEnd = null;
4697 }
4698
4699 public void removeUpdate(DocumentEvent e) {
4700 latestCommittedTextStart = latestCommittedTextEnd = null;
4701 }
4702 }
4703
4704
4705
4706
4707
4708
4709 private void replaceInputMethodText(InputMethodEvent e) {
4710 int commitCount = e.getCommittedCharacterCount();
4711 AttributedCharacterIterator text = e.getText();
4712 int composedTextIndex;
4713
4714
4715 Document doc = getDocument();
4716 if (composedTextExists()) {
4717 try {
4718 doc.remove(composedTextStart.getOffset(),
4719 composedTextEnd.getOffset() -
4720 composedTextStart.getOffset());
4721 } catch (BadLocationException ble) {}
4722 composedTextStart = composedTextEnd = null;
4723 composedTextAttribute = null;
4724 composedTextContent = null;
4725 }
4726
4727 if (text != null) {
4728 text.first();
4729 int committedTextStartIndex = 0;
4730 int committedTextEndIndex = 0;
4731
4732
4733 if (commitCount > 0) {
4734
4735 committedTextStartIndex = caret.getDot();
4736
4737
4738
4739 if (shouldSynthensizeKeyEvents()) {
4740 for (char c = text.current(); commitCount > 0;
4741 c = text.next(), commitCount--) {
4742 KeyEvent ke = new KeyEvent(this, KeyEvent.KEY_TYPED,
4743 EventQueue.getMostRecentEventTime(),
4744 0, KeyEvent.VK_UNDEFINED, c);
4745 processKeyEvent(ke);
4746 }
4747 } else {
4748 StringBuilder strBuf = new StringBuilder();
4749 for (char c = text.current(); commitCount > 0;
4750 c = text.next(), commitCount--) {
4751 strBuf.append(c);
4752 }
4753
4754
4755 mapCommittedTextToAction(strBuf.toString());
4756 }
4757
4758
4759 committedTextEndIndex = caret.getDot();
4760 }
4761
4762
4763 composedTextIndex = text.getIndex();
4764 if (composedTextIndex < text.getEndIndex()) {
4765 createComposedTextAttribute(composedTextIndex, text);
4766 try {
4767 replaceSelection(null);
4768 doc.insertString(caret.getDot(), composedTextContent,
4769 composedTextAttribute);
4770 composedTextStart = doc.createPosition(caret.getDot() -
4771 composedTextContent.length());
4772 composedTextEnd = doc.createPosition(caret.getDot());
4773 } catch (BadLocationException ble) {
4774 composedTextStart = composedTextEnd = null;
4775 composedTextAttribute = null;
4776 composedTextContent = null;
4777 }
4778 }
4779
4780
4781 if (committedTextStartIndex != committedTextEndIndex) {
4782 try {
4783 latestCommittedTextStart = doc.
4784 createPosition(committedTextStartIndex);
4785 latestCommittedTextEnd = doc.
4786 createPosition(committedTextEndIndex);
4787 } catch (BadLocationException ble) {
4788 latestCommittedTextStart =
4789 latestCommittedTextEnd = null;
4790 }
4791 } else {
4792 latestCommittedTextStart =
4793 latestCommittedTextEnd = null;
4794 }
4795 }
4796 }
4797
4798 private void createComposedTextAttribute(int composedIndex,
4799 AttributedCharacterIterator text) {
4800 Document doc = getDocument();
4801 StringBuilder strBuf = new StringBuilder();
4802
4803
4804 for (char c = text.setIndex(composedIndex);
4805 c != CharacterIterator.DONE; c = text.next()) {
4806 strBuf.append(c);
4807 }
4808
4809 composedTextContent = strBuf.toString();
4810 composedTextAttribute = new SimpleAttributeSet();
4811 composedTextAttribute.addAttribute(StyleConstants.ComposedTextAttribute,
4812 new AttributedString(text, composedIndex, text.getEndIndex()));
4813 }
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827 protected boolean saveComposedText(int pos) {
4828 if (composedTextExists()) {
4829 int start = composedTextStart.getOffset();
4830 int len = composedTextEnd.getOffset() -
4831 composedTextStart.getOffset();
4832 if (pos >= start && pos <= start + len) {
4833 try {
4834 getDocument().remove(start, len);
4835 return true;
4836 } catch (BadLocationException ble) {}
4837 }
4838 }
4839 return false;
4840 }
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851 protected void restoreComposedText() {
4852 Document doc = getDocument();
4853 try {
4854 doc.insertString(caret.getDot(),
4855 composedTextContent,
4856 composedTextAttribute);
4857 composedTextStart = doc.createPosition(caret.getDot() -
4858 composedTextContent.length());
4859 composedTextEnd = doc.createPosition(caret.getDot());
4860 } catch (BadLocationException ble) {}
4861 }
4862
4863
4864
4865
4866
4867
4868 private void mapCommittedTextToAction(String committedText) {
4869 Keymap binding = getKeymap();
4870 if (binding != null) {
4871 Action a = null;
4872 if (committedText.length() == 1) {
4873 KeyStroke k = KeyStroke.getKeyStroke(committedText.charAt(0));
4874 a = binding.getAction(k);
4875 }
4876
4877 if (a == null) {
4878 a = binding.getDefaultAction();
4879 }
4880
4881 if (a != null) {
4882 ActionEvent ae =
4883 new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
4884 committedText,
4885 EventQueue.getMostRecentEventTime(),
4886 getCurrentEventModifiers());
4887 a.actionPerformed(ae);
4888 }
4889 }
4890 }
4891
4892
4893
4894
4895
4896 private void setInputMethodCaretPosition(InputMethodEvent e) {
4897 int dot;
4898
4899 if (composedTextExists()) {
4900 dot = composedTextStart.getOffset();
4901 if (!(caret instanceof ComposedTextCaret)) {
4902 if (composedTextCaret == null) {
4903 composedTextCaret = new ComposedTextCaret();
4904 }
4905 originalCaret = caret;
4906
4907 exchangeCaret(originalCaret, composedTextCaret);
4908 }
4909
4910 TextHitInfo caretPos = e.getCaret();
4911 if (caretPos != null) {
4912 int index = caretPos.getInsertionIndex();
4913 dot += index;
4914 if (index == 0) {
4915
4916
4917 try {
4918 Rectangle d = modelToView(dot);
4919 Rectangle end = modelToView(composedTextEnd.getOffset());
4920 Rectangle b = getBounds();
4921 d.x += Math.min(end.x - d.x, b.width);
4922 scrollRectToVisible(d);
4923 } catch (BadLocationException ble) {}
4924 }
4925 }
4926 caret.setDot(dot);
4927 } else if (caret instanceof ComposedTextCaret) {
4928 dot = caret.getDot();
4929
4930 exchangeCaret(caret, originalCaret);
4931 caret.setDot(dot);
4932 }
4933 }
4934
4935 private void exchangeCaret(Caret oldCaret, Caret newCaret) {
4936 int blinkRate = oldCaret.getBlinkRate();
4937 setCaret(newCaret);
4938 caret.setBlinkRate(blinkRate);
4939 caret.setVisible(hasFocus());
4940 }
4941
4942
4943
4944
4945 private boolean shouldSynthensizeKeyEvents() {
4946 if (!checkedInputOverride) {
4947 checkedInputOverride = true;
4948 needToSendKeyTypedEvent =
4949 !isProcessInputMethodEventOverridden();
4950 }
4951 return needToSendKeyTypedEvent;
4952 }
4953
4954
4955
4956
4957
4958
4959 private boolean isProcessInputMethodEventOverridden() {
4960 if (overrideMap == null) {
4961 overrideMap = Collections.synchronizedMap(new HashMap<String, Boolean>());
4962 }
4963 Boolean retValue = overrideMap.get(getClass().getName());
4964
4965 if (retValue != null) {
4966 return retValue.booleanValue();
4967 }
4968 Boolean ret = AccessController.doPrivileged(new
4969 PrivilegedAction<Boolean>() {
4970 public Boolean run() {
4971 return isProcessInputMethodEventOverridden(
4972 JTextComponent.this.getClass());
4973 }
4974 });
4975
4976 return ret.booleanValue();
4977 }
4978
4979
4980
4981
4982 boolean composedTextExists() {
4983 return (composedTextStart != null);
4984 }
4985
4986
4987
4988
4989 class ComposedTextCaret extends DefaultCaret implements Serializable {
4990 Color bg;
4991
4992
4993
4994
4995 public void install(JTextComponent c) {
4996 super.install(c);
4997
4998 Document doc = c.getDocument();
4999 if (doc instanceof StyledDocument) {
5000 StyledDocument sDoc = (StyledDocument)doc;
5001 Element elem = sDoc.getCharacterElement(c.composedTextStart.getOffset());
5002 AttributeSet attr = elem.getAttributes();
5003 bg = sDoc.getBackground(attr);
5004 }
5005
5006 if (bg == null) {
5007 bg = c.getBackground();
5008 }
5009 }
5010
5011
5012
5013
5014 public void paint(Graphics g) {
5015 if(isVisible()) {
5016 try {
5017 Rectangle r = component.modelToView(getDot());
5018 g.setXORMode(bg);
5019 g.drawLine(r.x, r.y, r.x, r.y + r.height - 1);
5020 g.setPaintMode();
5021 } catch (BadLocationException e) {
5022
5023
5024 }
5025 }
5026 }
5027
5028
5029
5030
5031
5032 protected void positionCaret(MouseEvent me) {
5033 JTextComponent host = component;
5034 Point pt = new Point(me.getX(), me.getY());
5035 int offset = host.viewToModel(pt);
5036 int composedStartIndex = host.composedTextStart.getOffset();
5037 if ((offset < composedStartIndex) ||
5038 (offset > composedTextEnd.getOffset())) {
5039 try {
5040
5041 Position newPos = host.getDocument().createPosition(offset);
5042 host.getInputContext().endComposition();
5043
5044
5045
5046 EventQueue.invokeLater(new DoSetCaretPosition(host, newPos));
5047 } catch (BadLocationException ble) {
5048 System.err.println(ble);
5049 }
5050 } else {
5051
5052 super.positionCaret(me);
5053 }
5054 }
5055 }
5056
5057
5058
5059
5060 private class DoSetCaretPosition implements Runnable {
5061 JTextComponent host;
5062 Position newPos;
5063
5064 DoSetCaretPosition(JTextComponent host, Position newPos) {
5065 this.host = host;
5066 this.newPos = newPos;
5067 }
5068
5069 public void run() {
5070 host.setCaretPosition(newPos.getOffset());
5071 }
5072 }
5073 }